import { EcsComponent } from "./EcsComponent";

export class EcsEntity {
	/**
	 * 通过组件id列表获取分组id
	 * @param compIds 
	 * @returns 
	 */
	public static getGroupID(compIds: number[]): string {
		//const sorted= compIds.slice().sort((a, b) => { return a - b })
		let result = 0
		for (let i = 0; i < compIds.length; i++) {
			result += Math.pow(2, compIds[i]);
		}
		return result.toString()
		// return sorted.join(",");
	}
	public id: number = 0;
	public groupId: string = "";

	public componentMap: Map<number, EcsComponent> = new Map();
	public enabledComponentMap: Map<number, EcsComponent> = new Map();
	public __valid: boolean = false;
	_factory: EntityPool = null;
	constructor(factory: EntityPool) {
		this._factory = factory;
	}

	public recover() {
		// for (let i = 0; i < this.__comps.length; i++) {
		// 	if (this.__comps[i]) {
		// 		this.__comps[i].enable = false;
		// 	}
		// }
		this._factory.recover(this);
	}

	public destroy(): boolean {
		//TODO
		return true;
	}

	public get valid(): boolean {
		return this.__valid;
	}

	public get componentsID(): string {
		return this.groupId;
	}


	public component<T extends EcsComponent>(compClz: new () => T): T {
		return this.componentMap.get((compClz as any).__compId) as T;
	}

	hasAllCompIds(...compIds: number[]): boolean {
		for (let i = 0; i < compIds.length; i++) {
			if (!this.componentMap.get(compIds[i])) {
				return false
			}
		}
		return true
	}
}

export class EntityPool {
	public compIds: number[] = [];
	public _compDefs: { id: number, type: any, args: any[] }[] = [];
	public groupId: string = "";
	public _pool: EcsEntity[] = [];

	public constructor(components: (new () => EcsComponent)[], ...args: any[]) {
		this.defineComps(components, ...args);
	}

	/**定义组件 */
	private defineComp<T extends EcsComponent>(componentClz: new () => T, ...args: any[]): EntityPool {
		const componentId: number = EcsComponent.getIdFromClz(componentClz);
		this.compIds.push(componentId);
		this._compDefs.push({ id: componentId, type: componentClz, args: args });
		return this;
	}

	/**定义组件 */
	public defineComps(components: (new () => EcsComponent)[], ...args: any[]): EntityPool {
		components.forEach(element => {
			this.defineComp(element, args)
		});
		this.groupId = EcsEntity.getGroupID(this.compIds)

		return this;
	}

	static resetComp(comp: EcsComponent, cst: any) {
		cst.instance
		const instance = cst.instance()

		Object.assign(comp, instance)

		if (cst.__objPropKeys) {

			cst.__objPropKeys.forEach(key => {
				comp[key] = JSON.parse(JSON.stringify(instance[key]))
			});
		}
	}

	public create(entityId: number): EcsEntity {

		let _obj: EcsEntity = this._pool.length > 0 ? this._pool.pop() : null;
		if (_obj == null) {//对象池中没有
			_obj = new EcsEntity(this);
			for (let i = 0; i < this._compDefs.length; i++) {
				let _def = this._compDefs[i];
				let _comp = new _def.type(..._def.args);
				_obj.componentMap.set(_def.id, _comp);
			}
		}
		else {//从对象池直接获取的
			for (let i = 0; i < this._compDefs.length; i++) {
				let _def = this._compDefs[i];
				const _comp = _obj.componentMap.get(_def.id)
				EcsComponent.resetComp(_comp, _def.type)
			}
		}
		_obj.id = entityId
		_obj.groupId = this.groupId;
		for (let i = 0; i < this._compDefs.length; i++) {
			let _def = this._compDefs[i];
			_obj.componentMap.get(_def.id).__ownerId = _obj.id;
		}

		_obj.__valid = true;
		return _obj;
	}

	public recover(entity: EcsEntity): void {
		entity.id = 0;
		entity.__valid = false;
		this._pool.push(entity);
	}
}